﻿using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
using System.Web;
using System.IO;
using System.IO.Compression;
using System.IO.Packaging;
using Itasa.API;
using Itasa.RSS;

namespace Itasa
{
    internal class Download_Manager
    {

        internal TaskFactory tf;
        internal ConcurrentQueue<Object> downQueue;
        internal AutoResetEvent are;
        private CookieContainer Cookies;
        private DateTime ExpireDate;

        internal Download_Manager()
        {
            tf = new TaskFactory();
            downQueue = new ConcurrentQueue<Object>();
            are = new AutoResetEvent(false);
            ExpireDate = DateTime.MaxValue;
            Cookies = null;
            getCookies();
        }

        internal void ThreadMain()
        {
            Object url;
            try
            {
                while (true)
                {
                    if (!downQueue.TryDequeue(out url)) are.WaitOne();
                    else
                    {
                        if (Cookies == null || DateTime.Now >= ExpireDate) getCookies();
                        tf.StartNew(downloadTask, url);
                    }
                }
            }
            catch (ThreadAbortException)
            {
                if (Cookies == null || DateTime.Now >= ExpireDate) getCookies();
                while (downQueue.TryDequeue(out url))
                {
                    tf.StartNew(downloadTask, url);
                }
            }
        }

        private void writeFile(Stream inS, SubInfo info)
        {
            String path = Params.getDestPath(info);
            if (!Directory.Exists(@path)) Directory.CreateDirectory(@path);
            Stream file = File.Create(@Params.getFilePath(info));
            byte[] buffer = new byte[1024];
            int bytesRead;
            do
            {
                bytesRead = inS.Read(buffer, 0, buffer.Length);
                file.Write(buffer, 0, bytesRead);
            } while (bytesRead > 0);
            if (file != null) file.Close();
            Params.writeLog(info.FileName + " scaricato");
        }

        private void writeTorrent(Stream inS, String info)
        {
            String path = Config.TorrentsDir;
            if (!Directory.Exists(@path)) Console.WriteLine("Non c'e' la cartella downloads");
            //String fileName=info.Remove(0,info.LastIndexOf('/'));
            String fileName = String.Format("{0}.torrent", info);
            Stream file = File.Create(path+"\\"+fileName);
            byte[] buffer = new byte[1024];
            int bytesRead;
            do
            {
                bytesRead = inS.Read(buffer, 0, buffer.Length);
                file.Write(buffer, 0, bytesRead);
            } while (bytesRead > 0);
            if (file != null) file.Close();
            Params.writeLog(fileName + " scaricato");
        }

        private void getCookies()
        {
            if (Params.user != null)
            {
                try
                {
                    StringBuilder parameters = new StringBuilder();
                    parameters.AppendFormat("{0}={1}", "username", Config.ITASAusr);
                    parameters.AppendFormat("&{0}={1}", "passwd", Config.ITASApwd);
                    parameters.AppendFormat("&{0}={1}", "remember", "yes");
                    parameters.AppendFormat("&{0}={1}", "Submit", "Login");
                    parameters.AppendFormat("&{0}={1}", "option", "com_user");
                    parameters.AppendFormat("&{0}={1}", "task", "login");
                    parameters.AppendFormat("&{0}={1}", "silent", "true");
                    String data = parameters.ToString();

                    HttpWebRequest hwr = (HttpWebRequest)WebRequest.Create("http://www.italiansubs.net/index.php");
                    hwr.Method = "POST";
                    hwr.CookieContainer = new CookieContainer();
                    hwr.ContentType = "application/x-www-form-urlencoded";
                    hwr.ContentLength = data.Length;
                    Stream writeStream = hwr.GetRequestStream();
                    UTF8Encoding encoding = new UTF8Encoding();
                    byte[] bytes = encoding.GetBytes(data);
                    writeStream.Write(bytes, 0, bytes.Length);
                    HttpWebResponse response = (HttpWebResponse)hwr.GetResponse();
                    Stream responseStream = response.GetResponseStream();
                    StreamReader readStream = new StreamReader(responseStream, Encoding.UTF8);
                    String result = readStream.ReadToEnd();
                    CookieContainer cc = hwr.CookieContainer;
                    this.Cookies = cc;

                    foreach (Cookie c in cc.GetCookies(hwr.RequestUri))
                    {
                        if (c.Expires < this.ExpireDate) this.ExpireDate = c.Expires;
                    }
                }
                catch (WebException e)
                {
                    Params.writeLog("Errore nell'aggiornamento dei cookies: " + e.Message);
                }
            }
        }

        private void downloadTask(object url)
        {
            if (url is SubInfo)
            {
                if (Params.user != null)
                {
                    HttpWebRequest get;
                    HttpWebResponse response;
                    Stream responseStream;
                    StreamReader readStream;
                    String result;
                    try
                    {
                        get = (HttpWebRequest)WebRequest.Create("http://www.italiansubs.net/index.php?option=com_remository&Itemid=6&func=fileinfo&id=" + (url as SubInfo).ID);
                        get.Method = "GET";
                        get.CookieContainer = Cookies;
                        response = (HttpWebResponse)get.GetResponse();
                        responseStream = response.GetResponseStream();
                        readStream = new StreamReader(responseStream, Encoding.UTF8);
                        result = readStream.ReadToEnd();
                    }
                    catch
                    {
                        Params.writeLog("Errore nella richiesta del file " + (url as SubInfo).FileName);
                        return;
                    }
                    String link = null;
                    try
                    {
                        link = parseDownloadLink(result);
                    }
                    catch
                    {
                        Params.writeLog("Errore nella richiesta del file " + (url as SubInfo).FileName);
                        return;
                    }
                    try
                    {
                        get = (HttpWebRequest)WebRequest.Create(link);
                        get.Method = "GET";
                        get.CookieContainer = Cookies;
                        response = (HttpWebResponse)get.GetResponse();
                        responseStream = response.GetResponseStream();
                        writeFile(responseStream, (url as SubInfo));
                        if (response != null) response.Close();
                        if (responseStream != null) responseStream.Close();
                    }
                    catch
                    {
                        Params.writeLog("Errore nella ricezione del file " + (url as SubInfo).FileName);
                        return;
                    }
                }
                else Params.writeLog("Non puoi scaricare se non sei loggato");
            }
            else if (url is RSS_Torrent)
            {
                try
                {
                    HttpWebRequest get = (HttpWebRequest)WebRequest.Create((url as RSS_Torrent).Url);
                    get.Method = "GET";
                    get.CookieContainer = Cookies;
                    HttpWebResponse response = (HttpWebResponse)get.GetResponse();
                    Stream responseStream = response.GetResponseStream();
                    writeTorrent(responseStream, (url as RSS_Torrent).Name);
                    if (response != null) response.Close();
                    if (responseStream != null) responseStream.Close();
                }
                catch
                {
                    Params.writeLog("Errore nella ricezione del torrent " + (url as RSS_Torrent).Name);
                    return;
                }
            }
        }

        internal String parseDownloadLink(String s)
        {
            int i = s.IndexOf("<center><a href=\"");
            i += 17;
            int e = s.IndexOf("\" rel=\"nofollow\">");
            String url = s.Substring(i, e - i);
            return url;
        }

        internal void downloadSub(SubInfo link)
        {
            if (link != null)
            {
                downQueue.Enqueue(link);
                are.Set();
            }
        }

        internal void downloadTorrent(RSS_Torrent link)
        {
            if (link != null)
            {
                downQueue.Enqueue(link);
                are.Set();
            }
        }

    }
}
